#include "../include/Dictionary.h"
#include <fstream>
#include <sstream>
#include <iostream>
#include <stdlib.h>
//#include "CandidateResult.h"
using std::cout;
using std::endl;
using std::ifstream;
using std::istringstream;
Dictionary* Dictionary::_pInstance = Dictionary::getInstance();
Dictionary::Dictionary()
{
    readDict("../data/dict.txt");
    readIndex("../data/index.txt");
}

Dictionary::~Dictionary()
{

}

Dictionary* Dictionary::getInstance()
{
    if(_pInstance == nullptr)
    {
        _pInstance = new Dictionary();
        atexit(destory);
    }
    return _pInstance;
}

void Dictionary::destory()
{
    if(_pInstance)
    {
        delete _pInstance;
    }
}


vector<CandidateResult> Dictionary::doQuery(const string& key)
{
    set<CandidateResult> candidate;
    CandidateResult cr;
    size_t charnums = key.size() / nBytesCode(key[0]);
    for(size_t pos = 0, n = 0; n != charnums; ++pos, ++n)
    {
        size_t charlen = nBytesCode(key[pos]);
        string subWord = key.substr(pos,charlen);
        auto it_set = _index[subWord];
        //cout <<  "候选词的数量:" <<it_set.size() << endl;
        for(auto begin = it_set.begin(); begin != it_set.end(); ++begin)
        {
            cr._word = _dict[*begin].first;
            cr._freq = _dict[*begin].second;
            cr._dist = 0;
            cr._dist = distance(cr._word,key);
            candidate.insert(cr);
        }
        
    }
#if 0
    for(size_t idx = 0; idx < key.size(); idx++)
    {
        string tmp;
        tmp += key[idx];
        auto it_set = _index[tmp];
        cout <<  "候选词的数量:" <<it_set.size() << endl;
        for(auto begin = it_set.begin(); begin != it_set.end(); ++begin)
        {
            cr._word = _dict[*begin].first;
            cr._freq = _dict[*begin].second;
            cr._dist = 0;
            cr._dist = distance(cr._word,key);
            candidate.insert(cr);
        }
    }
#endif
    return vector<CandidateResult>(candidate.begin(),candidate.end());

}
void Dictionary::queryIndex()
{
    
}
int Dictionary::distance(string candidate,string key)
{
    return editDistance(candidate,key);
}
void Dictionary::readDict(const string& filename)
{
    ifstream ifs(filename);
    if(!ifs)
    {
        perror("ifs");
        return;
    }
    string line;
    int num = 0;
    while(getline(ifs,line))
    {
        string word;
        int freq;
        int flag = 0;
        istringstream iss(line);
        
        while(iss.good())
        {
            if(flag == 0)
            {
                iss >> word;
                flag = 1;
            }
            else
            {
                iss >> freq;
            }
        }
        _tmpDict[word] = num++;
        _dict.push_back(std::make_pair(word,freq));
    }
}
void Dictionary::readIndex(const string& filename)
{
    ifstream ifs(filename);
    if(!ifs)
    {
        perror("ifs");
        return;
    }

    string line;
    while(getline(ifs,line))
    {
        istringstream iss(line);
        string word;
        int  pos;
        int flag = 1;
        
        while(iss.good())
        {
            if(flag)
            {
                iss >> word;
                flag = 0;
                _index[word];
            }
            else
            {
                iss >> pos;
                _index[word].insert(pos);
            } 
        }
    }
    
}

void Dictionary::showDict() const                      //查看词典
{
    for(auto it = _dict.begin(); it != _dict.end(); it++)
    {
        cout << it->first << " " << it->second << endl;
    }
}


void Dictionary::showIndex() const
{
    for(auto it = _index.begin(); it != _index.end(); ++it)
    {
        cout << it->first << " ";
        for(auto it_set = it->second.begin(); it_set != it->second.end(); ++it_set)
        {
            cout << *it_set << " ";
        }
        cout << endl;
    }
}

size_t Dictionary::nBytesCode(const char ch)
{
    if(ch & (1 << 7))
    {
        int nBytes = 1;
        for(int idx = 0; idx != 6; ++idx)
        {
            if(ch & (1 << (6 - idx)))
            {
                ++nBytes;
            }
            else
            {
                break;
            }
        }
        return nBytes;
    }
    return 1;
}

std::size_t Dictionary::length(const std::string &str)
{
    std::size_t ilen = 0;
    for(std::size_t idx = 0; idx != str.size(); ++idx)
    {
        int nBytes = nBytesCode(str[idx]);
        idx += (nBytes - 1);
        ++ilen;
    }
    return ilen;
}
int Dictionary::triple_min(const int &a, const int &b, const int &c)
{
	return a < b ? (a < c ? a : c) : (b < c ? b : c);
}
int Dictionary::editDistance(const std::string &lhs, const std::string &rhs)
{
    //计算最小编辑距离-包括处理中英文
    size_t lhs_len = length(lhs);
    size_t rhs_len = length(rhs);
    int editDist[lhs_len + 1][rhs_len + 1];
    for(size_t idx = 0; idx <= lhs_len; ++idx)
    {
        editDist[idx][0] = idx;
    } 
    for(size_t idx = 0; idx <= rhs_len; ++idx)
    {
        editDist[0][idx] = idx;
    } 
    std::string sublhs, subrhs;
    for(std::size_t dist_i = 1, lhs_idx = 0; dist_i <= lhs_len; ++dist_i,
        ++lhs_idx)
    {
        size_t nBytes = nBytesCode(lhs[lhs_idx]);
        sublhs = lhs.substr(lhs_idx, nBytes);
        lhs_idx += (nBytes - 1);
        for(std::size_t dist_j = 1, rhs_idx = 0;dist_j <= rhs_len; ++dist_j, ++rhs_idx)
        {
            nBytes = nBytesCode(rhs[rhs_idx]);
            subrhs = rhs.substr(rhs_idx, nBytes);
            rhs_idx += (nBytes - 1);
            if(sublhs == subrhs)	
            {
                editDist[dist_i][dist_j] = editDist[dist_i - 1][dist_j -1];
            } 
            else
            {
                editDist[dist_i][dist_j] =
                    triple_min(editDist[dist_i][dist_j - 1] + 1,
                                editDist[dist_i - 1][dist_j] + 1,
                                editDist[dist_i - 1][dist_j - 1] + 1);
            }
        }
    } 
    return editDist[lhs_len][rhs_len];
}
